//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using System.Workflow.ComponentModel.Compiler;
using ManagementStudioServices.Interfaces;
using Microsoft.Research.ScientificWorkflow.ManagementStudioControls.Common;
using Microsoft.Research.ScientificWorkflow.ManagementStudioModels;
using Microsoft.Research.ScientificWorkflow.TridentUtilities;
using Microsoft.Research.ScientificWorkflow.UIDesigner;
using Microsoft.Research.ScientificWorkflow.UIDesigner.WpfComposite;
using Microsoft.Practices.Unity;
using Microsoft.Win32;
using SR = Microsoft.Research.DataLayer;
using System.Windows.Controls;
using System.Windows.Input;

namespace Microsoft.Research.ScientificWorkflow.ManagementStudioControls.RegistryManagerModule
{
    public class CategoryEditorPresenter : IRegistryManagerCenterPanePresenter, INotifyPropertyChanged
    {
        #region Private declarations

        private bool onDelete;

        private IUnityContainer container;

        private IRegistryManagerService registryManagerService;

        private CategoryViewModel editableCategoryModel;

        private CategoryViewModel selectedViewModel;

        private CategoryViewModel categoryPickerSelectedModel;

        private CategoryPicker categoryPicker;

        private UIHelper uiHelper;

        private bool saveInProgress;

        /// <summary>
        /// A control that indicates that there is some work happening in the background.
        /// </summary>
        private WaitControl waitControl;

        #endregion Private Declarations

        #region Constructor

        /// <summary>
        /// The presenter for the category manager.
        /// </summary>
        /// <param name="container">
        /// The unity container that enables this object to access all relevant items.
        /// </param>
        /// <param name="contentView">
        /// The main View.
        /// </param>
        /// <param name="leftPane">
        /// The left pane view.
        /// </param>
        /// <param name="service">
        /// The registry manager service giving access to the registry.
        /// </param>
        public CategoryEditorPresenter(IUnityContainer container, CategoryEditorView contentView, IRegistryManagerService service)
        {
            this.container = container;
            this.ContentView = contentView;
            this.registryManagerService = service;
            contentView.DataContext = this;

            this.DeleteCategoryCommand = new DelegateCommand<object>(p => this.DeleteCategoryExecute());
            this.SaveCategoryChangesCommand = new DelegateCommand<object[]>(this.SaveCategoryChangesExecute);
            this.CancelCategoryChangesCommand = new DelegateCommand<object>(p => this.CancelCategoryChangesExecute());
            this.NewCategoryCommand = new DelegateCommand<object>(p => this.CreateNewCategoryExecute());
            this.NewWorkflowCommand = new DelegateCommand<object>(p => this.NewWorkflowCommandExecute());
            this.ImportWorkflowCommand = new DelegateCommand<object>(p => this.ImportWorkflowCommandExecute());

            this.BrowseImageCommand = new DelegateCommand<object>(p => this.BrowseImageExecute());
            this.RevertToDefIconCommand = new DelegateCommand<object>(p => this.RevertToDefIconExecute());

            this.BrowseCategoryCommand = new DelegateCommand<object>(p => this.BrowseCategoryExecute());
            this.uiHelper = new UIHelper(this.registryManagerService.RegistryConnection);
            this.uiHelper.WorkflowImported += new EventHandler<ImportEventArgs>(this.OnWorkflowImported);

            // add handlers for the wait control functionality for import.
            this.uiHelper.AddWaitControl += new EventHandler<WaitMessageEventArgs>(this.OnAddWaitControl);
            this.uiHelper.RemoveWaitControl += new EventHandler<EventArgs>(this.OnRemoveWaitControl);
        }

        #endregion Constructor

        #region Properties

        /// <summary>
        /// Gets or sets the editable category model.
        /// </summary>
        /// <value>The editable category model.</value>
        public CategoryViewModel EditableCategoryModel
        {
            get
            {
                return this.editableCategoryModel;
            }

            set
            {
                this.editableCategoryModel = value;
                if (this.editableCategoryModel != null)
                {
                    this.NonSystemItem = this.editableCategoryModel.IsEditable;
                    this.OnNotifyPropertyChanged("NonSystemItem");
                }

                this.OnNotifyPropertyChanged("AllowDelete");
                this.OnNotifyPropertyChanged("EditableCategoryModel");
            }
        }

        /// <summary>
        /// Gets or sets the selected category view model.
        /// </summary>
        /// <value>The selected category view model.</value>
        public BaseRegMgrModel SelectedModel
        {
            get
            {
                return this.selectedViewModel;
            }
            set
            {
                this.selectedViewModel = value as CategoryViewModel;
                if (this.selectedViewModel != null)
                {
                    Guid currentId = this.selectedViewModel.Id;
                    if (null != this.EditableCategoryModel && !this.EditableCategoryModel.Id.Equals(currentId))
                    {
                        this.container.Resolve<IStatusMessageControl>().SetText(string.Empty);
                    }
                }

                this.EditableCategoryModel = CategoryViewModel.CreateClone(this.selectedViewModel);
                this.OnNotifyPropertyChanged("SelectedModel");
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether non-system created item.
        /// </summary>
        /// <value><c>true</c> if  non-system created item; otherwise, <c>false</c>.</value>
        public bool NonSystemItem
        {
            get;
            set;
        }

        /// <summary>
        /// Gets a value indicating whether allow delete.
        /// </summary>
        /// <value><c>true</c> if allow delete; otherwise, <c>false</c>.</value>
        public bool AllowDelete
        {
            get
            {
                bool newCategory = false;
                if (null != this.EditableCategoryModel)
                {
                    newCategory = this.EditableCategoryModel.Id.Equals(Guid.Empty);
                }

                return this.NonSystemItem && !newCategory;
            }
        }

        /// <summary>
        /// Gets or sets the delete category command.
        /// </summary>
        /// <value>The delete category command.</value>
        public DelegateCommand<object> DeleteCategoryCommand { get; private set; }

        /// <summary>
        /// Gets or sets the browse category command.
        /// </summary>
        /// <value>The browse category command.</value>
        public DelegateCommand<object> BrowseCategoryCommand { get; private set; }

        /// <summary>
        /// Gets or sets the save category changes command.
        /// </summary>
        /// <value>The save category changes command.</value>
        public DelegateCommand<object[]> SaveCategoryChangesCommand { get; private set; }

        /// <summary>
        /// Gets or sets the cancel category changes command.
        /// </summary>
        /// <value>The cancel category changes command.</value>
        public DelegateCommand<object> CancelCategoryChangesCommand { get; private set; }

        /// <summary>
        /// Gets or sets the new category command.
        /// </summary>
        /// <value>The new category command.</value>
        public DelegateCommand<object> NewCategoryCommand { get; private set; }

        /// <summary>
        /// Gets or sets the new workflow command.
        /// </summary>
        public DelegateCommand<object> NewWorkflowCommand { get; set; }

        /// <summary>
        /// Gets or sets the import workflow command.
        /// </summary>
        public DelegateCommand<object> ImportWorkflowCommand { get; set; }

        /// <summary>
        /// Gets or sets the browse image command.
        /// </summary>
        /// <value>The browse image command.</value>
        public DelegateCommand<object> BrowseImageCommand { get; private set; }

        /// <summary>
        /// Gets or sets the revert to def icon command.
        /// </summary>
        /// <value>The revert to def icon command.</value>
        public DelegateCommand<object> RevertToDefIconCommand { get; private set; }

        /// <summary>
        /// Gets or sets the content view.
        /// </summary>
        /// <value>The content view.</value>
        public UIElement ContentView { get; set; }

        /// <summary>
        /// Gets or sets the refresh command.
        /// </summary>
        /// <value>The refresh command.</value>
        public DelegateCommand<BaseRegMgrModel> RefreshCommand { get; set; }

        #endregion Properties

        #region INotifyPropertyChanged Members

        /// <summary>
        /// Occurs when a property value changes.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Called by a property when it wants to notify that its value has changed.
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        private void OnNotifyPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion

        #region Private Methods

        private SaveStateHandler EnforceSaveForChanges()
        {
            SaveStateHandler saveSuccess = new SaveStateHandler(SaveStatus.Valid);
            if (!saveInProgress
                && this.EditableCategoryModel != null
                && !this.EditableCategoryModel.Equals(this.SelectedModel as CategoryViewModel))
            {
                MessageBoxResult userResult = TridentMessageBox.ShowTridentConfirmationYesNoMessageBox(ManagementStudioResourceManager.GetString("SaveChangesToCategory"));
                if (userResult == MessageBoxResult.Yes)
                {
                    this.SaveCategoryChangesCommand.Execute(new object[] { false, saveSuccess });
                }
                else if (userResult == MessageBoxResult.No)
                {
                    this.Rollback();
                }
            }

            return saveSuccess;
        }

        private void BrowseCategoryExecute()
        {
            this.LaunchCategoryPicker();
            if (this.categoryPickerSelectedModel != null)
            {
                this.EditableCategoryModel.Parent = this.categoryPickerSelectedModel;
            }
        }

        private void LaunchCategoryPicker()
        {
            this.categoryPickerSelectedModel = null;
            CategoryViewModel parentModel = null;
            if (this.SelectedModel != null)
            {
                CategoryViewModel currentModel = this.SelectedModel as CategoryViewModel;
                parentModel = currentModel.Parent as CategoryViewModel;
            }

            this.categoryPicker = new CategoryPicker(this.container, this.FetchSelectedModelCategoryType(), parentModel);
            this.categoryPicker.CategoryPickerOk += new EventHandler<CategoryEventArgs>(this.OnCategoryPickerOk);
            this.categoryPicker.CategoryPickerClose += new EventHandler(this.OnCategoryPickerClose);
            this.categoryPicker.Owner = Application.Current.MainWindow;
            this.categoryPicker.ShowDialog();
        }

        private void OnCategoryPickerOk(object sender, CategoryEventArgs e)
        {
            if (e != null && this.EditableCategoryModel != null)
            {
                CategoryViewModel selectedModel = e.CategoryPickerSelectedModel;
                if (selectedModel != null)
                {
                    string errorMsg = string.Empty;
                    bool validSelection = this.CategorySelectionValidator(this.EditableCategoryModel, selectedModel, out errorMsg);
                    if (validSelection)
                    {
                        this.categoryPickerSelectedModel = selectedModel;
                        this.CloseCategoryPicker();
                    }
                    else if (!string.IsNullOrEmpty(errorMsg))
                    {
                        TridentMessageBox.ShowTridentErrorMessageBox(errorMsg);
                    }
                }
                else
                {
                    TridentMessageBox.ShowTridentErrorMessageBox(ManagementStudioResourceManager.GetString("SelectValidParent"));
                }
            }
        }

        private void OnCategoryPickerClose(object sender, EventArgs e)
        {
            this.CloseCategoryPicker();
        }

        private void CloseCategoryPicker()
        {
            if (this.categoryPicker != null)
            {
                this.categoryPicker.Close();
                this.categoryPicker = null;
            }
        }

        private bool CategorySelectionValidator(CategoryViewModel categoryViewModel, CategoryViewModel selectedParentModel, out string errorMsg)
        {
            bool valid = false;
            errorMsg = string.Empty;
            StringBuilder errorBuilder = new StringBuilder(ManagementStudioResourceManager.GetString("CategoryPickerInvalidSelection"));

            try
            {
                // Check if the category is a parent of the selectedParentCategory.
                valid = this.CheckCategoryParentAssignmentValidity(categoryViewModel, selectedParentModel);
                if (valid)
                {
                    if (!this.onDelete)
                    {
                        // Check if the category already exists.
                        valid = CategoryEditorPresenter.CheckCategoryUniqueNameConstraint(categoryViewModel, selectedParentModel);
                        if (valid)
                        {
                            // Check if the selected category is the uncategorized category. In that case this would be an invalid selection as
                            // there can be no child categories under uncategorized.
                            valid = CategoryEditorPresenter.CheckIfUncategorized(selectedParentModel);
                            if (!valid)
                            {
                                errorBuilder.Append(ManagementStudioResourceManager.GetString("UncategorizedSelectionInvalid"));
                            }
                        }
                        else
                        {
                            errorBuilder.Append(ManagementStudioResourceManager.GetString("CategoryNameNotUnique"));
                        }
                    }
                    // Do these checks only when activitys are being moved around, for example, delete.
                    else
                    {
                        // Check if the category has any Activitys attached to it, if yes, root as parentCategory is ruled out.
                        valid = this.CheckRootAssignment(categoryViewModel, selectedParentModel);
                        if (valid)
                        {
                            // Check if the category contains names at nested levels which will result in non-unique names if moved to a single category.
                            valid = this.CheckSelfUniqueNameConstraint(categoryViewModel);
                            if (valid)
                            {
                                // Check if the parent category has any activitys at the first level that have the same name as 
                                // any of the activitys at any level of the categoryViewModel.
                                valid = this.CheckActivityUniqueNameConstraint(categoryViewModel, this.registryManagerService.FetchCategoryActivitys(selectedParentModel));
                                if (!valid)
                                {
                                    errorBuilder.Append(ManagementStudioResourceManager.GetString("ItemNameNotUnique"));
                                }
                            }
                            else
                            {
                                errorBuilder.Append(ManagementStudioResourceManager.GetString("CategoryNonUniqueSelfNames"));
                            }
                        }
                        else
                        {
                            errorBuilder.Append(ManagementStudioResourceManager.GetString("CategoryPickerUnsupportedElementAtRoot"));
                        }
                    }
                }
                else
                {
                    errorBuilder.Append(ManagementStudioResourceManager.GetString("CategoryPickerCircularRef"));
                }
            }
            catch (TridentCustomException ex)
            {
                valid = false;
                errorBuilder.Append(ex.Message);
            }

            if (!valid)
            {
                errorMsg = errorBuilder.ToString();
            }

            return valid;
        }

        private bool CheckCategoryParentAssignmentValidity(CategoryViewModel categoryViewModel, CategoryViewModel selectedParentModel)
        {
            bool valid = true;
            if (categoryViewModel.Id.Equals(selectedParentModel.Id) || categoryViewModel.Children.Contains(selectedParentModel))
            {
                valid = false;
            }
            else
            {
                foreach (CategoryViewModel childModel in categoryViewModel.Children.OfType<CategoryViewModel>())
                {
                    valid = this.CheckCategoryParentAssignmentValidity(childModel, selectedParentModel);
                    if (!valid)
                    {
                        break;
                    }
                }
            }

            return valid;
        }

        private static bool CheckCategoryUniqueNameConstraint(CategoryViewModel categoryViewModel, CategoryViewModel selectedParentModel)
        {
            bool valid = false;
            if (!string.IsNullOrEmpty(categoryViewModel.Name) && !string.IsNullOrEmpty(categoryViewModel.Name.Trim()))
            {
                valid = !selectedParentModel.Children.OfType<CategoryViewModel>().Any(model => model.Name.Equals(categoryViewModel.Name.Trim(), StringComparison.OrdinalIgnoreCase)
                    && !model.Id.Equals(categoryViewModel.Id));
            }

            return valid;
        }

        private static bool CheckIfUncategorized(CategoryViewModel selectedParentModel)
        {
            bool isValid = true;
            if (selectedParentModel != null
                && selectedParentModel.CreatedBy.Equals("SYSTEM", StringComparison.Ordinal)
                && selectedParentModel.Name.Equals("Uncategorized", StringComparison.Ordinal))
            {
                isValid = false;
            }

            return isValid;
        }

        private bool CheckRootAssignment(CategoryViewModel categoryViewModel, CategoryViewModel selectedParentModel)
        {
            bool valid = true;
            Collection<WorkflowViewModel> categoryActivitys = this.registryManagerService.FetchCategoryActivitys(categoryViewModel);
            if (categoryActivitys.Count > 0 && categoryViewModel.RootCategory.Id.Equals(selectedParentModel.Id))
            {
                valid = false;
            }

            return valid;
        }

        private bool CheckActivityUniqueNameConstraint(CategoryViewModel categoryViewModel, Collection<WorkflowViewModel> parentActivitys)
        {
            bool valid = true;
            if (parentActivitys.Count > 0)
            {
                Collection<WorkflowViewModel> categoryActivitys = this.registryManagerService.FetchCategoryActivitys(categoryViewModel);
                if (parentActivitys.Intersect(categoryActivitys, new WorkflowModelComparer()).ToList().Count > 0)
                {
                    valid = false;
                }
                else
                {
                    foreach (CategoryViewModel childModel in categoryViewModel.Children.OfType<CategoryViewModel>())
                    {
                        valid = this.CheckActivityUniqueNameConstraint(childModel, parentActivitys);
                        if (!valid)
                        {
                            break;
                        }
                    }
                }
            }

            return valid;
        }

        private bool CheckSelfUniqueNameConstraint(CategoryViewModel categoryViewModel)
        {
            bool valid = true;
            if (categoryViewModel.Children.Count > 0)
            {
                List<WorkflowViewModel> categoryActivitys = new ObservableCollection<WorkflowViewModel>().ToList();
                valid = this.ContainsNonUniqueNamesOnFlatListing(categoryViewModel, categoryActivitys);
            }

            return valid;
        }

        private bool ContainsNonUniqueNamesOnFlatListing(CategoryViewModel parentModel, List<WorkflowViewModel> categoryActivitys)
        {
            bool valid = true;
            List<WorkflowViewModel> childActivitys = this.registryManagerService.FetchCategoryActivitys(parentModel).ToList();
            if (categoryActivitys.Intersect(childActivitys, new WorkflowModelComparer()).ToList().Count > 0)
            {
                valid = false;
            }

            if (valid)
            {
                categoryActivitys.AddRange(childActivitys.AsEnumerable());
                foreach (CategoryViewModel childModel in parentModel.Children.OfType<CategoryViewModel>())
                {
                    valid = this.ContainsNonUniqueNamesOnFlatListing(childModel, categoryActivitys);
                    if (!valid)
                    {
                        break;
                    }
                }
            }

            return valid;
        }

        private void SaveCategoryChangesExecute(object[] parameters)
        {
            bool saveSucceeded = true;
            this.saveInProgress = true;
            StringBuilder errorMsg = new StringBuilder(ManagementStudioResourceManager.GetString("SaveErrorRegistryMgr"));
            try
            {
                saveSucceeded = this.PreSaveValidation();
                if (saveSucceeded)
                {
                    SR.Namespace updatedNamespace = this.registryManagerService.SaveCategory(this.EditableCategoryModel);
                    saveSucceeded = updatedNamespace != null;
                    if (saveSucceeded)
                    {
                        this.EditableCategoryModel.Update(updatedNamespace);
                        this.EditableCategoryModel.IsSelected = true;
                    }
                }
                else
                {
                    errorMsg.Append(" ");
                    errorMsg.Append(ManagementStudioResourceManager.GetString("InvalidPreSaveCheck"));
                }
            }
            catch (TridentCustomException ex)
            {
                errorMsg.Append(ex.Message);
                saveSucceeded = false;
            }

            if (saveSucceeded)
            {
                if (this.UpdateCommand != null)
                {
                    this.UpdateCommand.Execute(this.EditableCategoryModel);
                    this.EditableCategoryModel = CategoryViewModel.CreateClone(this.SelectedModel as CategoryViewModel);
                }

                this.container.Resolve<IStatusMessageControl>().SetText(ManagementStudioResourceManager.GetString("SaveSuccessCategoryMgr"));
            }
            else
            {
                TridentMessageBox.ShowTridentErrorMessageBox(errorMsg.ToString());
            }

            if (parameters != null && parameters.Length > 1)
            {
                SaveStateHandler saveSuccess = parameters[1] as SaveStateHandler;
                saveSuccess.SaveOptionSelected = saveSucceeded ? SaveStatus.Valid : SaveStatus.Invalid;
                if (!saveSucceeded && !this.SelectedModel.IsSelected)
                {
                    CategoryViewModel backUpModel = CategoryViewModel.CreateClone(this.EditableCategoryModel);
                    this.Rollback();
                    this.SelectedModel.IsSelected = true;
                    this.EditableCategoryModel = CategoryViewModel.CreateClone(backUpModel);
                }
            }

            this.saveInProgress = false;
        }

        private bool PreSaveValidation()
        {
            bool readyForSave = false;
            if (this.EditableCategoryModel != null
                && !string.IsNullOrEmpty(this.EditableCategoryModel.Name)
                && !string.IsNullOrEmpty(this.EditableCategoryModel.Name.Trim())
                && this.EditableCategoryModel.Parent != null
                && Helper.CheckNameForValidCharacters(this.EditableCategoryModel.Name.Trim())
                && CategoryEditorPresenter.CheckCategoryUniqueNameConstraint(this.EditableCategoryModel, this.EditableCategoryModel.Parent as CategoryViewModel))
            {
                readyForSave = true;
            }

            return readyForSave;
        }

        private void CancelCategoryChangesExecute()
        {
            this.Rollback();
            if (this.SelectRootCommand != null)
            {
                this.SelectRootCommand.Execute(null);
            }
        }

        private void Rollback()
        {
            if (this.SelectedModel != null)
            {
                this.EditableCategoryModel = CategoryViewModel.CreateClone(this.SelectedModel as CategoryViewModel);
            }
        }

        private void RevertToDefIconExecute()
        {
            this.EditableCategoryModel.Icon = null;
            this.EditableCategoryModel.IconPath = string.Empty;
        }

        private void BrowseImageExecute()
        {
            string fileSelected = string.Empty;

            OpenFileDialog openDialog = new OpenFileDialog();

            // Filters the XOML file in the current Directory.
            openDialog.Filter = "Image Files (*.png, *.jpg, *.jpeg, *.ico, *.bmp)|*.png; *.jpg; *.jpeg; *.ico; *.bmp";

            // SUer should select only one file to open.
            openDialog.Multiselect = false;

            // Checks and promts the user if the file is not present in the directory.
            openDialog.CheckFileExists = true;

            // Check if File Exists in directory Specified.
            openDialog.CheckPathExists = true;

            // Restores the previous Directory the user had selected to Open/Save the file.
            openDialog.RestoreDirectory = true;

            if ((bool)openDialog.ShowDialog())
            {
                // Get the selected file name.
                fileSelected = openDialog.FileName;
            }

            if (!string.IsNullOrEmpty(fileSelected) && File.Exists(fileSelected))
            {
                string selectedExtn = System.IO.Path.GetExtension(fileSelected);
                bool validFile = (selectedExtn.Equals(".png", StringComparison.OrdinalIgnoreCase)
                    || selectedExtn.Equals(".ico", StringComparison.OrdinalIgnoreCase)
                    || selectedExtn.Equals(".jpg", StringComparison.OrdinalIgnoreCase)
                    || selectedExtn.Equals(".jpeg", StringComparison.OrdinalIgnoreCase)
                    || selectedExtn.Equals(".bmp", StringComparison.OrdinalIgnoreCase));
                if (validFile)
                {
                    this.EditableCategoryModel.IconPath = fileSelected;
                }
                else
                {
                    TridentMessageBox.ShowTridentErrorMessageBox(ManagementStudioResourceManager.GetString("InvalidImageFileSelection"));
                    this.BrowseImageCommand.Execute(null);
                }
            }
        }

        private void CreateNewCategoryExecute()
        {
            BaseRegMgrModel parentModel = null;
            if (this.SelectedModel != null)
            {
                parentModel = this.SelectedModel;
                if (this.SelectedModel.Id.Equals(Guid.Empty))
                {
                    parentModel = this.SelectedModel.Parent;
                }

                if (parentModel != null && !(parentModel as CategoryViewModel).AllowChildCategories)
                {
                    parentModel = null;
                }
            }

            this.SelectedModel = new CategoryViewModel(this.FetchSelectedModelCategoryType(), parentModel);
        }

        /// <summary>
        /// Handler for New Workflow command
        /// </summary>
        private void NewWorkflowCommandExecute()
        {
            try
            {
                this.registryManagerService.OpenComposerForNewWorkflow();
            }
            catch (TridentCustomException ex)
            {
                TridentErrorHandler.HandleTridentCustomExceptionInUI(ex);
            }
            catch (Exception ex)
            {
                TridentErrorHandler.HandleUIException(ex);
            }
        }

        /// <summary>
        /// Handler for Import Workflow Command
        /// </summary>
        private void ImportWorkflowCommandExecute()
        {
            try
            {
                SaveStateHandler saveState = this.EnforceSaveForChanges();
                if (saveState.SaveOptionSelected != SaveStatus.Invalid)
                {

                    this.uiHelper.ImportWorkflow(this.registryManagerService.RegistryConnection);
                }
            }
            catch (Exception ex)
            {
                TridentErrorHandler.HandleUIException(ex);
            }
        }

        /// <summary>
        /// This function used to add the wait control to the parent grid during the import activity process.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnRemoveWaitControl(object sender, EventArgs e)
        {
            // Get the top-most grid of the main window.
            Grid parentGrid = Application.Current.MainWindow.Content as Grid;
            if (parentGrid != null)
            {
                // Enable all child elements.
                foreach (UIElement element in parentGrid.Children)
                {
                    element.IsEnabled = true;
                }

                // Add the wait control.
                parentGrid.Children.Remove(this.waitControl);
            }
            Application.Current.MainWindow.Cursor = Cursors.Arrow;
        }

        /// <summary>
        /// This function used to remove the wait control after the import of activity completes.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnAddWaitControl(object sender, WaitMessageEventArgs e)
        {
            // If parent grid cannot be retrieved, add a wait cursor.
            Application.Current.MainWindow.Cursor = Cursors.Wait;

            // Get the top-most grid of the main window.
            Grid parentGrid = Application.Current.MainWindow.Content as Grid;
            if (parentGrid != null)
            {
                // Create an instance of the wait control.
                if (this.waitControl == null)
                {
                    this.waitControl = new WaitControl(e.WaitMessage);
                    Grid.SetRowSpan(this.waitControl, 3);
                }
                // Disable all existing children in this grid.
                foreach (UIElement element in parentGrid.Children)
                {
                    element.IsEnabled = false;
                }

                // Add the wait control.
                parentGrid.Children.Add(this.waitControl);
            }
            else
            {
                // If parent grid cannot be retrieved, add a wait cursor.
                Application.Current.MainWindow.Cursor = Cursors.Wait;
            }
        }

        /// <summary>
        /// This event is fired to retrieve the status of the import process for workflow.
        /// </summary>
        /// <param name="sender">sender object</param>
        /// <param name="e">event arguments</param>
        private void OnWorkflowImported(object sender, ImportEventArgs e)
        {
            string message = ManagementStudioResourceManager.GetString("ImportfaliureWorkflow");
            if (!e.Status)
            {
                // Get the error string returned from the exception.
                if (!string.IsNullOrEmpty(e.ErrorMessage))
                    message += e.ErrorMessage;
                TridentMessageBox.ShowTridentErrorMessageBox(Application.Current.MainWindow, message);
            }
            else
            {
                if (this.RefreshCommand != null)
                {
                    this.RefreshCommand.Execute(this.SelectedModel);
                }

                this.container.Resolve<IStatusMessageControl>().SetText(ManagementStudioResourceManager.GetString("ImportSuccessWorkflow"));
            }
        }

        /// <summary>
        /// Returns a value indicating if the selected category has any workflows at any level of nesting.
        /// </summary>
        /// <param name="selectedModel">
        /// Selected model.
        /// </param>
        /// <returns>
        /// True if it finds a workflow, False otherwise.
        /// </returns>
        private bool ContainsWorkflow(CategoryViewModel selectedModel)
        {
            bool containsWorkflow = false;
            if (selectedModel != null)
            {
                if (selectedModel.Children.Any(child => child is WorkflowCatalogViewModel || child is ActivityViewModel))
                {
                    containsWorkflow = true;
                }
                else
                {
                    foreach (BaseRegMgrModel currentModel in selectedModel.Children)
                    {
                        containsWorkflow = this.ContainsWorkflow(currentModel as CategoryViewModel);
                        if (containsWorkflow)
                        {
                            break;
                        }
                    }
                }
            }

            return containsWorkflow;
        }

        private void DeleteCategoryExecute()
        {
            if (this.SelectedModel != null && !this.SelectedModel.Id.Equals(Guid.Empty))
            {
                MessageBoxResult res = TridentMessageBox.ShowTridentConfirmationYesNoMessageBox(ManagementStudioResourceManager.GetString("CategoryDeleteConfirmationMsg"));
                if (res == MessageBoxResult.Yes)
                {
                    if (this.ContainsWorkflow(this.SelectedModel as CategoryViewModel))
                    {
                        this.onDelete = true;
                        this.LaunchCategoryPicker();
                        this.onDelete = false;
                        if (this.categoryPickerSelectedModel == null)
                        {
                            return;
                        }
                    }

                    BaseRegMgrModel backUpOfDeleteModel = this.SelectedModel;
                    CategoryViewModel selectedModel = this.categoryPickerSelectedModel;
                    StringBuilder errorMsg = new StringBuilder(ManagementStudioResourceManager.GetString("CategoryDeleteError"));
                    bool deleteSuccess = false;
                    try
                    {
                        this.EditableCategoryModel = null;
                        deleteSuccess = this.registryManagerService.DeleteWorkflowCategory(this.SelectedModel as CategoryViewModel, selectedModel);
                    }
                    catch (TridentCustomException ex)
                    {
                        deleteSuccess = false;
                        errorMsg.Append(ex.Message);
                    }

                    if (this.DeleteCommand != null)
                    {
                        this.DeleteCommand.Execute(backUpOfDeleteModel);
                    }

                    if (deleteSuccess)
                    {
                        this.container.Resolve<IStatusMessageControl>().SetText(ManagementStudioResourceManager.GetString("CategoryDeleteSuccess"));
                    }
                    else
                    {
                        TridentMessageBox.ShowTridentErrorMessageBox(errorMsg.ToString());
                    }
                }
            }
        }

        private CategoryType FetchSelectedModelCategoryType()
        {
            CategoryType categoryType = CategoryType.Activity;
            if (this.SelectedModel != null)
            {
                categoryType = (this.SelectedModel as CategoryViewModel).CurrentCategoryType;
            }

            return categoryType;
        }

        #endregion Private Methods

        #region IRegistryManagerCenterPanePresenter Members

        /// <summary>
        /// Saves the changes on the view.
        /// </summary>
        /// <returns>
        /// Value indicating success or failure of the save.
        /// </returns>
        public SaveStateHandler SaveChanges()
        {
            return this.EnforceSaveForChanges();
        }

        /// <summary>
        /// Gets or sets the delete command.
        /// </summary>
        /// <value>The delete command.</value>
        public DelegateCommand<BaseRegMgrModel> DeleteCommand { get; set; }

        /// <summary>
        /// Gets or sets the update command.
        /// </summary>
        /// <value>The delete command.</value>
        public DelegateCommand<BaseRegMgrModel> UpdateCommand { get; set; }

        /// <summary>
        /// Gets or sets the select root command.
        /// </summary>
        /// <value>The select root command.</value>
        public DelegateCommand<object> SelectRootCommand { get; set; }

        #endregion
    }
}
